package handler

import (
	"fitness/go-admin/internal/model"
	"fitness/go-admin/internal/service"
	"fitness/go-admin/pkg/response"
	wsManager "fitness/go-admin/pkg/websocket"
	"fmt"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"log"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// ChatHandler 客服聊天处理器
type ChatHandler struct {
	chatService *service.ChatService
	fileService service.FileService
	wsManager   *wsManager.Manager
}

// NewChatHandler 创建客服聊天处理器
func NewChatHandler(chatService *service.ChatService, fileService service.FileService) *ChatHandler {
	return &ChatHandler{
		chatService: chatService,
		fileService: fileService,
		wsManager:   wsManager.GetManager(),
	}
}

// ==================== WebSocket 连接 ====================

// ConnectWebSocket 建立WebSocket连接
// @Summary 建立WebSocket连接
// @Description 用户建立WebSocket连接以接收实时消息
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Router /api/v1/chat/ws [get]
func (h *ChatHandler) ConnectWebSocket(c *gin.Context) {
	// 从上下文获取用户信息（由Auth中间件注入）
	userID, exists := c.Get("userID")
	if !exists {
		response.Error(c, 401, "未授权")
		return
	}

	username, _ := c.Get("username")

	uid := userID.(uint)
	uname := ""
	if username != nil {
		uname = username.(string)
	}

	// 升级HTTP连接为WebSocket
	upgrader := wsManager.GetUpgrader()
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		response.Error(c, 500, fmt.Sprintf("WebSocket升级失败: %v", err))
		return
	}

	// 创建客户端（ID包含时间戳确保唯一性）
	client := &wsManager.Client{
		ID:       fmt.Sprintf("user_%d_%d", uid, time.Now().UnixNano()),
		UserID:   uid,
		Username: uname,
		Conn:     conn,
		Send:     make(chan []byte, 256),
		Manager:  h.wsManager,
	}

	// 注册客户端
	h.wsManager.Register(client)

	// 推送离线消息（异步）
	go func() {
		time.Sleep(500 * time.Millisecond) // 等待连接稳定
		if err := h.chatService.PushOfflineMessages(uid, client); err != nil {
			log.Printf("[WebSocket] 推送离线消息失败: %v", err)
		}
	}()

	// 启动读写协程
	go client.WritePump()
	go client.ReadPump()
}

// ==================== 会话管理 ====================

// CreateSession 创建会话
// @Summary 创建客服会话
// @Description 会员创建新的客服或教练咨询会话
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param request body model.CreateSessionReq true "创建会话请求"
// @Success 200 {object} response.Response{data=model.ChatSession}
// @Router /api/v1/chat/sessions [post]
func (h *ChatHandler) CreateSession(c *gin.Context) {
	userID := c.GetUint("userID")

	var req model.CreateSessionReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, err.Error())
		return
	}

	session, err := h.chatService.CreateSession(userID, req.Type, req.Title)
	if err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, session, "")
}

// GetSessions 获取会话列表
// @Summary 获取会话列表
// @Description 获取用户的会话列表
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param status query string false "会话状态"
// @Param page query int false "页码"
// @Param pageSize query int false "每页数量"
// @Success 200 {object} response.Response{data=model.SessionListResp}
// @Router /api/v1/chat/sessions [get]
func (h *ChatHandler) GetSessions(c *gin.Context) {
	userID := c.GetUint("userID")

	var req model.SessionListReq
	if err := c.ShouldBindQuery(&req); err != nil {
		response.BadRequest(c, err.Error())
		return
	}

	result, err := h.chatService.GetUserSessions(userID, req.Status, req.Page, req.PageSize)
	if err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, result, "")
}

// GetSession 获取会话详情
// @Summary 获取会话详情
// @Description 获取指定会话的详细信息
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "会话ID"
// @Success 200 {object} response.Response{data=model.ChatSession}
// @Router /api/v1/chat/sessions/:id [get]
func (h *ChatHandler) GetSession(c *gin.Context) {
	userID := c.GetUint("userID")
	sessionID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		response.BadRequest(c, "无效的会话ID")
		return
	}

	session, err := h.chatService.GetSession(uint(sessionID), userID)
	if err != nil {
		response.Error(c, 404, err.Error())
		return
	}

	response.Success(c, session, "")
}

// CloseSession 关闭会话
// @Summary 关闭会话
// @Description 关闭指定的会话
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "会话ID"
// @Param request body model.CloseSessionReq false "关闭会话请求"
// @Success 200 {object} response.Response
// @Router /api/v1/chat/sessions/:id/close [post]
func (h *ChatHandler) CloseSession(c *gin.Context) {
	userID := c.GetUint("userID")
	sessionID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		response.BadRequest(c, "无效的会话ID")
		return
	}

	var req model.CloseSessionReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, err.Error())
		return
	}

	if err := h.chatService.CloseSession(uint(sessionID), userID, req.Rating, req.RatingComment); err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, nil, "")
}

// ==================== 消息管理 ====================

// SendMessage 发送消息
// @Summary 发送消息
// @Description 在会话中发送消息
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param request body model.SendMessageReq true "发送消息请求"
// @Success 200 {object} response.Response{data=model.ChatMessage}
// @Router /api/v1/chat/messages [post]
func (h *ChatHandler) SendMessage(c *gin.Context) {
	userID := c.GetUint("userID")

	var req model.SendMessageReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, err.Error())
		return
	}

	message, err := h.chatService.SendMessage(userID, &req)
	if err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, message, "")
}

// GetMessages 获取消息列表
// @Summary 获取消息列表
// @Description 获取会话的消息列表
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param sessionId query int true "会话ID"
// @Param page query int false "页码"
// @Param pageSize query int false "每页数量"
// @Param beforeId query int false "获取指定消息之前的消息"
// @Success 200 {object} response.Response{data=model.MessageListResp}
// @Router /api/v1/chat/messages [get]
func (h *ChatHandler) GetMessages(c *gin.Context) {
	userID := c.GetUint("userID")

	var req model.MessageListReq
	if err := c.ShouldBindQuery(&req); err != nil {
		response.BadRequest(c, err.Error())
		return
	}

	result, err := h.chatService.GetMessages(req.SessionID, userID, req.Page, req.PageSize, req.BeforeID)
	if err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, result, "")
}

// MarkMessagesAsRead 标记消息已读
// @Summary 标记消息已读
// @Description 标记指定的消息为已读
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param request body model.MarkReadReq true "标记已读请求"
// @Success 200 {object} response.Response
// @Router /api/v1/chat/messages/read [post]
func (h *ChatHandler) MarkMessagesAsRead(c *gin.Context) {
	userID := c.GetUint("userID")

	var req model.MarkReadReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, err.Error())
		return
	}

	// 获取第一条消息的会话ID
	if len(req.MessageIDs) == 0 {
		response.BadRequest(c, "消息ID列表不能为空")
		return
	}

	// TODO: 验证所有消息都属于同一个会话
	// 这里简化处理，实际应该验证
	sessionID := uint(0) // 需要从消息中获取

	if err := h.chatService.MarkMessagesAsRead(sessionID, userID, req.MessageIDs); err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, nil, "")
}

// GetUnreadCount 获取未读消息数
// @Summary 获取未读消息数
// @Description 获取用户所有会话的未读消息总数
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Success 200 {object} response.Response{data=map[string]int64}
// @Router /api/v1/chat/unread-count [get]
func (h *ChatHandler) GetUnreadCount(c *gin.Context) {
	userID := c.GetUint("userID")

	count, err := h.chatService.GetUserUnreadCount(userID)
	if err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, map[string]int64{
		"unreadCount": count,
	}, "")
}

// NotifyTyping 通知正在输入
// @Summary 通知正在输入
// @Description 通知对方用户正在输入
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param sessionId query int true "会话ID"
// @Param isTyping query bool true "是否正在输入"
// @Success 200 {object} response.Response
// @Router /api/v1/chat/typing [post]
func (h *ChatHandler) NotifyTyping(c *gin.Context) {
	userID := c.GetUint("userID")
	username := c.GetString("username")

	sessionIDStr := c.Query("sessionId")
	sessionID, err := strconv.ParseUint(sessionIDStr, 10, 32)
	if err != nil {
		response.BadRequest(c, "无效的会话ID")
		return
	}

	isTypingStr := c.Query("isTyping")
	isTyping := isTypingStr == "true" || isTypingStr == "1"

	if err := h.chatService.NotifyTyping(uint(sessionID), userID, username, isTyping); err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, nil, "")
}

// ==================== 客服管理（管理员/教练功能） ====================

// GetWaitingSessions 获取等待中的会话
// @Summary 获取等待中的会话（客服端）
// @Description 客服获取所有等待分配的会话
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Success 200 {object} response.Response{data=[]model.SessionItem}
// @Router /api/v1/chat/staff/waiting [get]
func (h *ChatHandler) GetWaitingSessions(c *gin.Context) {
	sessions, err := h.chatService.GetWaitingSessions()
	if err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, sessions, "")
}

// AssignSession 分配会话
// @Summary 分配会话给客服
// @Description 管理员将等待中的会话分配给指定客服
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "会话ID"
// @Param request body model.AssignSessionReq true "分配会话请求"
// @Success 200 {object} response.Response
// @Router /api/v1/chat/staff/sessions/:id/assign [post]
func (h *ChatHandler) AssignSession(c *gin.Context) {
	sessionID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		response.BadRequest(c, "无效的会话ID")
		return
	}

	var req model.AssignSessionReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, err.Error())
		return
	}

	if err := h.chatService.AssignSession(uint(sessionID), req.StaffID); err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, nil, "")
}

// TakeSession 客服接入会话
// @Summary 客服主动接入会话
// @Description 客服主动接入一个等待中的会话
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "会话ID"
// @Success 200 {object} response.Response
// @Router /api/v1/chat/staff/sessions/:id/take [post]
func (h *ChatHandler) TakeSession(c *gin.Context) {
	userID := c.GetUint("userID")
	sessionID, err := strconv.ParseUint(c.Param("id"), 10, 32)
	if err != nil {
		response.BadRequest(c, "无效的会话ID")
		return
	}

	if err := h.chatService.AssignSession(uint(sessionID), userID); err != nil {
		response.Error(c, 500, err.Error())
		return
	}

	response.Success(c, nil, "")
}

// GetOnlineStatus 获取在线状态
// @Summary 获取在线状态
// @Description 获取WebSocket连接状态和在线用户数
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Success 200 {object} response.Response{data=map[string]interface{}}
// @Router /api/v1/chat/online-status [get]
func (h *ChatHandler) GetOnlineStatus(c *gin.Context) {
	onlineCount := h.wsManager.GetOnlineCount()

	response.Success(c, map[string]interface{}{
		"online":      true,
		"onlineCount": onlineCount,
	}, "")
}

// ==================== 消息撤回 ====================

// RecallMessage 撤回消息
// @Summary 撤回消息
// @Description 撤回2分钟内发送的消息
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "消息ID"
// @Success 200 {object} response.Response
// @Router /api/v1/chat/messages/{id}/recall [post]
func (h *ChatHandler) RecallMessage(c *gin.Context) {
	userID := c.GetUint("userID")

	// 获取消息ID
	messageIDStr := c.Param("id")
	messageID, err := strconv.ParseUint(messageIDStr, 10, 32)
	if err != nil {
		response.Error(c, 400, "消息ID格式错误")
		return
	}

	// 调用 Service 撤回消息
	err = h.chatService.RecallMessage(uint(messageID), userID)
	if err != nil {
		response.Error(c, 400, err.Error())
		return
	}

	response.Success(c, nil, "消息已撤回")
}

// ==================== 文件上传 ====================

// UploadChatFile 上传聊天文件
// @Summary 上传聊天文件
// @Description 上传聊天中的图片或文件，上传后自动发送消息
// @Tags 客服系统
// @Accept multipart/form-data
// @Produce json
// @Security Bearer
// @Param sessionId formData int true "会话ID"
// @Param file formData file true "文件"
// @Success 200 {object} response.Response{data=model.ChatMessage}
// @Router /api/v1/chat/upload [post]
func (h *ChatHandler) UploadChatFile(c *gin.Context) {
	userID := c.GetUint("userID")

	// 获取会话ID
	sessionIDStr := c.PostForm("sessionId")
	sessionID, err := strconv.ParseUint(sessionIDStr, 10, 32)
	if err != nil {
		response.Error(c, 400, "会话ID格式错误")
		return
	}

	// 验证会话权限
	session, err := h.chatService.GetSession(uint(sessionID), userID)
	if err != nil {
		response.Error(c, 403, "无权上传文件到此会话")
		return
	}

	// 获取上传的文件
	fileHeader, err := c.FormFile("file")
	if err != nil {
		response.Error(c, 400, "未找到上传文件")
		return
	}

	// 验证文件大小（最大 50MB）
	maxSize := int64(50 * 1024 * 1024)
	if fileHeader.Size > maxSize {
		response.Error(c, 400, "文件大小不能超过50MB")
		return
	}

	// 判断文件类型
	fileExt := filepath.Ext(fileHeader.Filename)
	fileExtLower := strings.ToLower(fileExt)

	var messageType string

	// 图片类型
	imageExts := []string{".jpg", ".jpeg", ".png", ".gif", ".webp"}
	isImage := false
	for _, ext := range imageExts {
		if fileExtLower == ext {
			isImage = true
			messageType = "IMAGE"
			break
		}
	}

	// 文件类型
	if !isImage {
		allowedExts := []string{".pdf", ".doc", ".docx", ".xls", ".xlsx", ".zip", ".rar"}
		isAllowed := false
		for _, ext := range allowedExts {
			if fileExtLower == ext {
				isAllowed = true
				break
			}
		}
		if !isAllowed {
			response.Error(c, 400, "不支持的文件类型")
			return
		}
		messageType = "FILE"
	}

	// 上传文件到文件服务
	uploadReq := &model.UploadFileReq{}

	fileResp, err := h.fileService.UploadFile(fileHeader, uploadReq)
	if err != nil {
		response.Error(c, 500, fmt.Sprintf("文件上传失败: %v", err))
		return
	}

	// 如果是图片，获取图片尺寸
	imageWidth := 0
	imageHeight := 0
	if isImage {
		// 打开文件获取尺寸
		file, err := fileHeader.Open()
		if err == nil {
			defer file.Close()
			config, _, err := image.DecodeConfig(file)
			if err == nil {
				imageWidth = config.Width
				imageHeight = config.Height
			}
		}
	}

	// 构建完整URL
	fullURL := fileResp.FileURL
	if !strings.HasPrefix(fullURL, "http") {
		// 如果是相对路径，保持原样（前端会自动拼接域名）
		fullURL = fileResp.FileURL
	}

	// 自动发送文件消息
	sendReq := &model.SendMessageReq{
		SessionID:   uint(sessionID),
		MessageType: messageType,
		FileURL:     fullURL,
		FileName:    fileResp.FileName,
		FileSize:    fileResp.FileSize,
		ImageWidth:  imageWidth,
		ImageHeight: imageHeight,
	}

	message, err := h.chatService.SendMessage(userID, sendReq)
	if err != nil {
		response.Error(c, 500, fmt.Sprintf("发送消息失败: %v", err))
		return
	}

	log.Printf("[文件上传] 用户 %d 在会话 %d 上传了文件: %s (大小: %d)",
		userID, session.ID, fileResp.FileName, fileResp.FileSize)

	response.Success(c, message, "文件上传成功")
}

// ==================== 消息搜索 ====================

// SearchMessages 搜索消息
// @Summary 搜索消息
// @Description 在指定会话中搜索关键词
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param sessionId query int true "会话ID"
// @Param keyword query string true "搜索关键词"
// @Param page query int false "页码"
// @Param pageSize query int false "每页数量"
// @Success 200 {object} response.Response
// @Router /api/v1/chat/messages/search [get]
func (h *ChatHandler) SearchMessages(c *gin.Context) {
	userID := c.GetUint("userID")

	// 获取参数
	sessionIDStr := c.Query("sessionId")
	sessionID, err := strconv.ParseUint(sessionIDStr, 10, 32)
	if err != nil {
		response.Error(c, 400, "会话ID格式错误")
		return
	}

	keyword := c.Query("keyword")
	if keyword == "" {
		response.Error(c, 400, "搜索关键词不能为空")
		return
	}

	// 分页参数
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "20"))

	// 搜索消息
	messages, total, err := h.chatService.SearchMessages(userID, uint(sessionID), keyword, page, pageSize)
	if err != nil {
		response.Error(c, 400, err.Error())
		return
	}

	// 构造响应
	result := map[string]interface{}{
		"list":     messages,
		"total":    total,
		"page":     page,
		"pageSize": pageSize,
		"keyword":  keyword,
	}

	response.Success(c, result, "")
}

// ==================== 会话转接 ====================

// TransferSession 转接会话
// @Summary 转接会话
// @Description 客服将会话转接给其他客服
// @Tags 客服系统
// @Accept json
// @Produce json
// @Security Bearer
// @Param id path int true "会话ID"
// @Param request body object true "转接请求 {toStaffId: 目标客服ID}"
// @Success 200 {object} response.Response
// @Router /api/v1/chat/staff/sessions/{id}/transfer [post]
func (h *ChatHandler) TransferSession(c *gin.Context) {
	userID := c.GetUint("userID")

	// 获取会话ID
	sessionIDStr := c.Param("id")
	sessionID, err := strconv.ParseUint(sessionIDStr, 10, 32)
	if err != nil {
		response.Error(c, 400, "会话ID格式错误")
		return
	}

	// 获取目标客服ID
	var req struct {
		ToStaffID uint `json:"toStaffId" binding:"required"`
	}
	if err := c.ShouldBindJSON(&req); err != nil {
		response.Error(c, 400, "参数错误")
		return
	}

	// 转接会话
	err = h.chatService.TransferSession(uint(sessionID), userID, req.ToStaffID)
	if err != nil {
		response.Error(c, 400, err.Error())
		return
	}

	response.Success(c, nil, "会话转接成功")
}
